home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / program / gcc / ixemul-4.lha / ixemul-41.4 / network / res_send.c < prev    next >
C/C++ Source or Header  |  1995-05-18  |  11KB  |  432 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #if defined(LIBC_SCCS) && !defined(lint)
  35. static char sccsid[] = "@(#)res_send.c    6.27 (Berkeley) 2/24/91";
  36. #endif /* LIBC_SCCS and not lint */
  37.  
  38. /*
  39.  * Send query to name server and wait for reply.
  40.  */
  41.  
  42. #include <sys/param.h>
  43. #include <sys/time.h>
  44. #include <sys/socket.h>
  45. #include <sys/uio.h>
  46. #include <netinet/in.h>
  47. #include <arpa/nameser.h>
  48. #include <stdio.h>
  49. #include <errno.h>
  50. #include <resolv.h>
  51. #include <unistd.h>
  52. #include <string.h>
  53.  
  54. static int s = -1;    /* socket used for communications */
  55. static struct sockaddr no_addr;
  56.  
  57. #ifndef FD_SET
  58. #define    NFDBITS        32
  59. #define    FD_SETSIZE    32
  60. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  61. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  62. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  63. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  64. #endif
  65.  
  66. res_send(buf, buflen, answer, anslen)
  67.     const char *buf;
  68.     int buflen;
  69.     char *answer;
  70.     int anslen;
  71. {
  72.     register int n;
  73.     int try, v_circuit, resplen, ns;
  74.     int gotsomewhere = 0, connected = 0;
  75.     int connreset = 0;
  76.     u_short id, len;
  77.     char *cp;
  78.     fd_set dsmask;
  79.     struct timeval timeout;
  80.     HEADER *hp = (HEADER *) buf;
  81.     HEADER *anhp = (HEADER *) answer;
  82.     struct iovec iov[2];
  83.     int terrno = ETIMEDOUT;
  84.     char junk[512];
  85.  
  86. #ifdef DEBUG
  87.     if (_res.options & RES_DEBUG) {
  88.         printf("res_send()\n");
  89.         __p_query(buf);
  90.     }
  91. #endif DEBUG
  92.     if (!(_res.options & RES_INIT))
  93.         if (res_init() == -1) {
  94.             return(-1);
  95.         }
  96.     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  97.     id = hp->id;
  98.     /*
  99.      * Send request, RETRY times, or until successful
  100.      */
  101.     for (try = 0; try < _res.retry; try++) {
  102.        for (ns = 0; ns < _res.nscount; ns++) {
  103. #ifdef DEBUG
  104.         if (_res.options & RES_DEBUG)
  105.             printf("Querying server (# %d) address = %s\n", ns+1,
  106.                   inet_ntoa(_res.nsaddr_list[ns].sin_addr));
  107. #endif DEBUG
  108.     usevc:
  109.         if (v_circuit) {
  110.             int truncated = 0;
  111.  
  112.             /*
  113.              * Use virtual circuit;
  114.              * at most one attempt per server.
  115.              */
  116.             try = _res.retry;
  117.             if (s < 0) {
  118.                 s = socket(AF_INET, SOCK_STREAM, 0);
  119.                 if (s < 0) {
  120.                     terrno = errno;
  121. #ifdef DEBUG
  122.                     if (_res.options & RES_DEBUG)
  123.                         perror("socket (vc) failed");
  124. #endif DEBUG
  125.                     continue;
  126.                 }
  127.                 if (connect(s,
  128.                     (struct sockaddr *)&(_res.nsaddr_list[ns]),
  129.                     sizeof(struct sockaddr)) < 0) {
  130.                     terrno = errno;
  131. #ifdef DEBUG
  132.                     if (_res.options & RES_DEBUG)
  133.                         perror("connect failed");
  134. #endif DEBUG
  135.                     (void) close(s);
  136.                     s = -1;
  137.                     continue;
  138.                 }
  139.             }
  140.             /*
  141.              * Send length & message
  142.              */
  143.             len = htons((u_short)buflen);
  144.             iov[0].iov_base = (caddr_t)&len;
  145.             iov[0].iov_len = sizeof(len);
  146.             iov[1].iov_base = (char *)buf;
  147.             iov[1].iov_len = buflen;
  148.             if (writev(s, iov, 2) != sizeof(len) + buflen) {
  149.                 terrno = errno;
  150. #ifdef DEBUG
  151.                 if (_res.options & RES_DEBUG)
  152.                     perror("write failed");
  153. #endif DEBUG
  154.                 (void) close(s);
  155.                 s = -1;
  156.                 continue;
  157.             }
  158.             /*
  159.              * Receive length & response
  160.              */
  161.             cp = answer;
  162.             len = sizeof(short);
  163.             while (len != 0 &&
  164.                 (n = read(s, (char *)cp, (int)len)) > 0) {
  165.                 cp += n;
  166.                 len -= n;
  167.             }
  168.             if (n <= 0) {
  169.                 terrno = errno;
  170. #ifdef DEBUG
  171.                 if (_res.options & RES_DEBUG)
  172.                     perror("read failed");
  173. #endif DEBUG
  174.                 (void) close(s);
  175.                 s = -1;
  176.                 /*
  177.                  * A long running process might get its TCP
  178.                  * connection reset if the remote server was
  179.                  * restarted.  Requery the server instead of
  180.                  * trying a new one.  When there is only one
  181.                  * server, this means that a query might work
  182.                  * instead of failing.  We only allow one reset
  183.                  * per query to prevent looping.
  184.                  */
  185.                 if (terrno == ECONNRESET && !connreset) {
  186.                     connreset = 1;
  187.                     ns--;
  188.                 }
  189.                 continue;
  190.             }
  191.             cp = answer;
  192.             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  193. #ifdef DEBUG
  194.                 if (_res.options & RES_DEBUG)
  195.                     fprintf(stderr, "response truncated\n");
  196. #endif DEBUG
  197.                 len = anslen;
  198.                 truncated = 1;
  199.             } else
  200.                 len = resplen;
  201.             while (len != 0 &&
  202.                (n = read(s, (char *)cp, (int)len)) > 0) {
  203.                 cp += n;
  204.                 len -= n;
  205.             }
  206.             if (n <= 0) {
  207.                 terrno = errno;
  208. #ifdef DEBUG
  209.                 if (_res.options & RES_DEBUG)
  210.                     perror("read failed");
  211. #endif DEBUG
  212.                 (void) close(s);
  213.                 s = -1;
  214.                 continue;
  215.             }
  216.             if (truncated) {
  217.                 /*
  218.                  * Flush rest of answer
  219.                  * so connection stays in synch.
  220.                  */
  221.                 anhp->tc = 1;
  222.                 len = resplen - anslen;
  223.                 while (len != 0) {
  224.                     n = (len > sizeof(junk) ?
  225.                         sizeof(junk) : len);
  226.                     if ((n = read(s, junk, n)) > 0)
  227.                         len -= n;
  228.                     else
  229.                         break;
  230.                 }
  231.             }
  232.         } else {
  233.             /*
  234.              * Use datagrams.
  235.              */
  236.             if (s < 0) {
  237.                 s = socket(AF_INET, SOCK_DGRAM, 0);
  238.                 if (s < 0) {
  239.                     terrno = errno;
  240. #ifdef DEBUG
  241.                     if (_res.options & RES_DEBUG)
  242.                         perror("socket (dg) failed");
  243. #endif DEBUG
  244.                     continue;
  245.                 }
  246.             }
  247. #if    BSD >= 43
  248.             /*
  249.              * I'm tired of answering this question, so:
  250.              * On a 4.3BSD+ machine (client and server,
  251.              * actually), sending to a nameserver datagram
  252.              * port with no nameserver will cause an
  253.              * ICMP port unreachable message to be returned.
  254.              * If our datagram socket is "connected" to the
  255.              * server, we get an ECONNREFUSED error on the next
  256.              * socket operation, and select returns if the
  257.              * error message is received.  We can thus detect
  258.              * the absence of a nameserver without timing out.
  259.              * If we have sent queries to at least two servers,
  260.              * however, we don't want to remain connected,
  261.              * as we wish to receive answers from the first
  262.              * server to respond.
  263.              */
  264.             if (_res.nscount == 1 || (try == 0 && ns == 0)) {
  265.                 /*
  266.                  * Don't use connect if we might
  267.                  * still receive a response
  268.                  * from another server.
  269.                  */
  270.                 if (connected == 0) {
  271.             if (connect(s, (struct sockaddr *)&_res.nsaddr_list[ns],
  272.                         sizeof(struct sockaddr)) < 0) {
  273. #ifdef DEBUG
  274.                         if (_res.options & RES_DEBUG)
  275.                             perror("connect");
  276. #endif DEBUG
  277.                         continue;
  278.                     }
  279.                     connected = 1;
  280.                 }
  281.                 if (send(s, buf, buflen, 0) != buflen) {
  282. #ifdef DEBUG
  283.                     if (_res.options & RES_DEBUG)
  284.                         perror("send");
  285. #endif DEBUG
  286.                     continue;
  287.                 }
  288.             } else {
  289.                 /*
  290.                  * Disconnect if we want to listen
  291.                  * for responses from more than one server.
  292.                  */
  293.                 if (connected) {
  294.                     (void) connect(s, &no_addr,
  295.                         sizeof(no_addr));
  296.                     connected = 0;
  297.                 }
  298. #endif BSD
  299.                 if (sendto(s, buf, buflen, 0,
  300.                     (struct sockaddr *)&_res.nsaddr_list[ns],
  301.                     sizeof(struct sockaddr)) != buflen) {
  302. #ifdef DEBUG
  303.                     if (_res.options & RES_DEBUG)
  304.                         perror("sendto");
  305. #endif DEBUG
  306.                     continue;
  307.                 }
  308. #if    BSD >= 43
  309.             }
  310. #endif
  311.  
  312.             /*
  313.              * Wait for reply
  314.              */
  315.             timeout.tv_sec = (_res.retrans << try);
  316.             if (try > 0)
  317.                 timeout.tv_sec /= _res.nscount;
  318.             if (timeout.tv_sec <= 0)
  319.                 timeout.tv_sec = 1;
  320.             timeout.tv_usec = 0;
  321. wait:
  322.             FD_ZERO(&dsmask);
  323.             FD_SET(s, &dsmask);
  324.             n = select(s+1, &dsmask, (fd_set *)NULL,
  325.                 (fd_set *)NULL, &timeout);
  326.             if (n < 0) {
  327. #ifdef DEBUG
  328.                 if (_res.options & RES_DEBUG)
  329.                     perror("select");
  330. #endif DEBUG
  331.                 continue;
  332.             }
  333.             if (n == 0) {
  334.                 /*
  335.                  * timeout
  336.                  */
  337. #ifdef DEBUG
  338.                 if (_res.options & RES_DEBUG)
  339.                     printf("timeout\n");
  340. #endif DEBUG
  341. #if BSD >= 43
  342.                 gotsomewhere = 1;
  343. #endif
  344.                 continue;
  345.             }
  346.             if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
  347. #ifdef DEBUG
  348.                 if (_res.options & RES_DEBUG)
  349.                     perror("recvfrom");
  350. #endif DEBUG
  351.                 continue;
  352.             }
  353.             gotsomewhere = 1;
  354.             if (id != anhp->id) {
  355.                 /*
  356.                  * response from old query, ignore it
  357.                  */
  358. #ifdef DEBUG
  359.                 if (_res.options & RES_DEBUG) {
  360.                     printf("old answer:\n");
  361.                     __p_query(answer);
  362.                 }
  363. #endif DEBUG
  364.                 goto wait;
  365.             }
  366.             if (!(_res.options & RES_IGNTC) && anhp->tc) {
  367.                 /*
  368.                  * get rest of answer;
  369.                  * use TCP with same server.
  370.                  */
  371. #ifdef DEBUG
  372.                 if (_res.options & RES_DEBUG)
  373.                     printf("truncated answer\n");
  374. #endif DEBUG
  375.                 (void) close(s);
  376.                 s = -1;
  377.                 v_circuit = 1;
  378.                 goto usevc;
  379.             }
  380.         }
  381. #ifdef DEBUG
  382.         if (_res.options & RES_DEBUG) {
  383.             printf("got answer:\n");
  384.             __p_query(answer);
  385.         }
  386. #endif DEBUG
  387.         /*
  388.          * If using virtual circuits, we assume that the first server
  389.          * is preferred * over the rest (i.e. it is on the local
  390.          * machine) and only keep that one open.
  391.          * If we have temporarily opened a virtual circuit,
  392.          * or if we haven't been asked to keep a socket open,
  393.          * close the socket.
  394.          */
  395.         if ((v_circuit &&
  396.             ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
  397.             (_res.options & RES_STAYOPEN) == 0) {
  398.             (void) close(s);
  399.             s = -1;
  400.         }
  401.         return (resplen);
  402.        }
  403.     }
  404.     if (s >= 0) {
  405.         (void) close(s);
  406.         s = -1;
  407.     }
  408.     if (v_circuit == 0)
  409.         if (gotsomewhere == 0)
  410.             errno = ECONNREFUSED;    /* no nameservers found */
  411.         else
  412.             errno = ETIMEDOUT;    /* no answer obtained */
  413.     else
  414.         errno = terrno;
  415.     return (-1);
  416. }
  417.  
  418. /*
  419.  * This routine is for closing the socket if a virtual circuit is used and
  420.  * the program wants to close it.  This provides support for endhostent()
  421.  * which expects to close the socket.
  422.  *
  423.  * This routine is not expected to be user visible.
  424.  */
  425. _res_close()
  426. {
  427.     if (s != -1) {
  428.         (void) close(s);
  429.         s = -1;
  430.     }
  431. }
  432.